package com.uum.admin.controller;

import cn.hutool.core.date.DateUtil;
import com.uum.admin.service.SysLoginLogService;
import com.uum.admin.service.SysOperationLogService;
import com.uum.admin.service.SysWebVisitService;
import com.uum.common.core.constant.RedisConstants;
import com.uum.common.core.result.Result;
import com.uum.web.util.DateUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Api(tags = "统计访问接口")
@RestController
@RequestMapping("/api/v1/visit")
@RequiredArgsConstructor
public class VisitController {

    private final SysLoginLogService loginLogService;
    private final SysOperationLogService operationLogService;
    private final SysWebVisitService webVisitService;
    private final RedisTemplate redisTemplate;
    private final RedissonClient redissonClient;


    @SneakyThrows
    @ApiOperation(value = "获取一周访问量")
    @GetMapping("getVisitByWeek")
    public Result getVisitByWeek() {
        Map<String, Object> resultMap;
        resultMap = (Map<String, Object>) redisTemplate.opsForValue().get(RedisConstants.WEEK_VISIT);
        if (resultMap == null) {
            //占锁
            RLock lock = redissonClient.getLock(RedisConstants.LOCK_WEEK_VISIT);
            // 尝试加锁，最多等待5秒，上锁以后10秒自动解锁
            boolean tryLock = lock.tryLock(5, 10, TimeUnit.SECONDS);
            if (tryLock) {
                try {
                    //获取最近七天的日期
                    List<String> weekList = DateUtils.getDaysByN(7, "yyyy-MM-dd");
                    //上周
                    String lastWeek = DateUtil.formatDate(DateUtil.lastWeek());
                    String tomorrow = DateUtil.tomorrow().toString();
                    String today = DateUtil.today();
                    String yesterday = DateUtil.formatDate(DateUtil.yesterday());

                    //统计最近七天内的web访问量由 当天 + 前6天组成 当天数据存放在redis,前6天数据存在数据库
                    //统计前6天的web访问量(PV)
                    List<Map<String, Object>> webPV = webVisitService.getWebPVByWeek(lastWeek, yesterday);
                    //统计前6天的web独立用户数(UV) 目前通过IP来统计
                    List<Map<String, Object>> webUV = webVisitService.getWebUVByWeek(lastWeek, yesterday);

                    Map<String, Object> webPVMap = new HashMap<>();
                    Map<String, Object> webUVMap = new HashMap<>();

                    for (Map<String, Object> item : webPV) {
                        webPVMap.put(item.get("DATE").toString(), item.get("COUNT"));
                    }

                    for (Map<String, Object> item : webUV) {
                        webUVMap.put(item.get("DATE").toString(), item.get("COUNT"));
                    }

                    //统计最近七天内的后台访问量(PV)
                    List<Map<String, Object>> adminPV = operationLogService.getPVByWeek(lastWeek, tomorrow);
                    //统计七天内独立用户数(UV) 目前通过IP来统计
                    List<Map<String, Object>> adminUV = loginLogService.getUVByWeek(lastWeek, tomorrow);

                    Map<String, Object> adminPVMap = new HashMap<>();
                    Map<String, Object> adminUVMap = new HashMap<>();

                    for (Map<String, Object> item : adminPV) {
                        adminPVMap.put(item.get("DATE").toString(), item.get("COUNT"));
                    }

                    for (Map<String, Object> item : adminUV) {
                        adminUVMap.put(item.get("DATE").toString(), item.get("COUNT"));
                    }

                    //web访问量数组
                    List<Long> webPVList = new ArrayList<>(7);
                    //web独立用户数组
                    List<Long> webUVList = new ArrayList<>(7);
                    //后台访问量数组
                    List<Long> adminPVList = new ArrayList<>(7);
                    //后台独立用户数组
                    List<Long> adminUVList = new ArrayList<>(7);

                    for (int i = 0; i < weekList.size(); i++) {
                        String day = weekList.get(i);
                        if (webPVMap.get(day) != null) {
                            BigDecimal pvNumber = (BigDecimal) webPVMap.get(day);
                            Long uvNumber = (Long) webUVMap.get(day);
                            webPVList.add(pvNumber.longValue());
                            webUVList.add(uvNumber);
                        } else {
                            if (i == weekList.size() - 1 ) {
                                //从redis中获取当天web端的数据
                                String key = RedisConstants.WEB_PV + today;
                                Boolean webHasKey = redisTemplate.hasKey(key);
                                if (webHasKey) {
                                    Set uvSet = redisTemplate.opsForHash().keys(key);
                                    int uv = uvSet.size();
                                    webUVList.add( Long.valueOf(uv));
                                    List<Integer> values = redisTemplate.opsForHash().values(key);
                                    Integer pv = values.stream().collect(Collectors.summingInt(Integer::intValue));
                                    webPVList.add( Long.valueOf(pv));
                                } else {
                                    webUVList.add(0l);
                                    webPVList.add(0l);
                                }
                            } else {
                                webPVList.add(0l);
                                webUVList.add(0l);
                            }
                        }

                        if (adminPVMap.get(day) != null) {
                            Long pvNumber = (Long) adminPVMap.get(day);
                            Long uvNumber = (Long) adminUVMap.get(day);
                            adminPVList.add(pvNumber);
                            adminUVList.add(uvNumber);
                        } else {
                            adminPVList.add(0l);
                            adminUVList.add(0l);
                        }
                    }

                    resultMap = new HashMap<>(3);
                    resultMap.put("date", weekList);
                    resultMap.put("adminPV", adminPVList);
                    resultMap.put("adminUV", adminUVList);
                    resultMap.put("webPV", webPVList);
                    resultMap.put("webUV", webUVList);
                    // 将一周访问量存入Redis中【过期时间10分钟】
                    redisTemplate.opsForValue().set(RedisConstants.WEEK_VISIT, resultMap, 10, TimeUnit.MINUTES);
                } finally {
                    lock.unlock();
                }
            }
        }

        return Result.success(resultMap);
    }

}
